home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’94 / [√] Distribution Restricted! / Steve Sisak / TMFutures / Futures.c < prev    next >
Text File  |  1994-06-26  |  6KB  |  254 lines

  1. /*
  2.     File:        ThreadFuturesInternal.c
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Written by:    xxx put writers here xxx
  7.  
  8.     Copyright:    © 1993 by Apple Computer, Inc., all rights reserved.
  9.                 © 1994 by Steve Sisak, all rights reserved.
  10.  
  11. NOTE:
  12.     Need to check w/Dave Falkenberg at Apple for proper credit
  13.     for all previous writers of this code and proper copyright
  14.     before distribution
  15.  
  16.     Change History (most recent first):
  17.  
  18.          <1>    10/14/93    bsp        first checked in
  19.  
  20. */
  21.  
  22. #include "Futures.h"
  23. #include <Threads.h>
  24. #include <GestaltEqu.h>
  25.  
  26. pascal OSErr    IsFutureBlock(AppleEvent* message);
  27. pascal OSErr    DoThreadBlock(AppleEvent* message);
  28. pascal OSErr    DoThreadUnblock(AppleEvent* message);
  29.  
  30. #define kAERefconAttribute            'refc'
  31. #define kAENonexistantAttribute        'gag!'
  32.  
  33. #define kImmediateTimeout            0
  34.  
  35. #define    kInitialThreadsInPool        5
  36. #define    kMinimumNumberOfFreeThreads    2
  37.  
  38.  
  39. struct ThreadList
  40. {
  41.     short        numThreads;
  42.     ThreadID    threads[1];
  43. };
  44.  
  45. typedef struct ThreadList ThreadList, *ThreadListPtr, **ThreadListHdl;
  46.  
  47. #define sizeofThreadList(numthreads) (sizeof(ThreadList) + ((numthreads)-1)*sizeof(ThreadID))
  48.  
  49. pascal OSErr InitFutures(void)
  50. {
  51.     OSErr            theErr = noErr;
  52.     long            aResponse;
  53.     
  54.     theErr = Gestalt(gestaltThreadMgrAttr, &aResponse);
  55.  
  56.     if (theErr)
  57.         return(theErr);
  58.  
  59.     theErr = AEInstallSpecialHandler('blck', (ProcPtr) DoThreadBlock, false);
  60.     theErr = AEInstallSpecialHandler('unbk', (ProcPtr) DoThreadUnblock, false);
  61.  
  62.     return(theErr);
  63. }
  64.  
  65. pascal OSErr DoThreadBlock(AppleEvent* message)
  66. {
  67.     OSErr                    theErr = noErr;
  68.     DescType                actualType;
  69.     Size                    actualSize;
  70.     ThreadListHdl            threadList;
  71.     ThreadID                currentThread;
  72.     
  73.     //    Apparently the current thread needs to access some information, which 
  74.     //    is really a future.  We need to see if there is already a list of threads
  75.     //    blocked on this message.  If there isn't, create an empty list.  Add
  76.     //    the current thread to the list.  Sleep the current thread.
  77.  
  78.     //    We need to have a critical section because we are appending to the blocked
  79.     //    queue list.  If we get pre-empted during this code, that could really screw
  80.     //    our list up.  We probably won't get pre-empted, because we were called
  81.     //    from the AE Manager.  But its better to be safe than sorry.
  82.     
  83.     ThreadBeginCritical();
  84.  
  85.         theErr = GetCurrentThread(¤tThread);
  86.  
  87.         theErr = AEGetAttributePtr(message, kAERefconAttribute, 
  88.             typeLongInteger, &actualType, (Ptr) &threadList, sizeof(threadList), &actualSize);
  89.     
  90.         if (theErr == errAEDescNotFound || !threadList)
  91.         {
  92.             // If we can't find a waiting thread list, then create one containing 
  93.             // just ourself and put it back in the message
  94.         
  95.             threadList = (ThreadListHdl) NewHandle(sizeofThreadList(1));
  96.             
  97.             theErr = MemError();
  98.  
  99.             (**threadList).numThreads = 1;
  100.             (**threadList).threads[0] = currentThread;
  101.  
  102.             theErr = AEPutAttributePtr(message, kAERefconAttribute, typeLongInteger,
  103.                                        (Ptr) &threadList, sizeof(threadList));
  104.             theErr = noErr;
  105.         }
  106.         else
  107.         {
  108.             // Otherwise just append ourself onto the existing list
  109.         
  110.             short numWaiting = (**threadList).numThreads;
  111.         
  112.             SetHandleSize((Handle) threadList, sizeofThreadList(numWaiting+1));
  113.     
  114.             theErr = MemError();
  115.             
  116.             (**threadList).threads[numWaiting] = currentThread;
  117.             (**threadList).numThreads = ++numWaiting;
  118.         }
  119.     
  120.     // If there was an error setting don't block (I think)
  121.     
  122.     if (theErr == noErr)    
  123.         theErr = SetThreadStateEndCritical(currentThread, kStoppedThreadState, kNoThreadID);
  124.     else
  125.         ThreadEndCritical();
  126.  
  127.     return(theErr);
  128. }
  129.  
  130. pascal OSErr DoThreadUnblock(AppleEvent* message)
  131. {
  132.     OSErr                    theErr = noErr;
  133.     DescType                actualType;
  134.     Size                    actualSize;
  135.     ThreadState                blockedThreadState;
  136.     ThreadListHdl            threadList;
  137.  
  138.     //    This message has just turned real.  If there is a list of threads blocked 
  139.     //    because they tried to access the data, walk through the list of blocked
  140.     //    threads waking and deallocating the list element as you go.
  141.  
  142.     theErr = AEGetAttributePtr(message, kAERefconAttribute,
  143.         typeLongInteger, &actualType, (Ptr) &threadList, sizeof(threadList), &actualSize);
  144.     
  145.     if (theErr == errAEDescNotFound || !threadList)
  146.     {
  147.         //    It's possible that this unblocking handler will get called for ALL replies
  148.         //    to apple events, not just futures.  If that's the case, then getting
  149.         //    the above error is not really an error.  Clear it and just return.
  150.     
  151.         theErr = noErr;
  152.     }
  153.     else
  154.     {
  155.         //    We probably won't be pre-empted, but why take the chance?  We need to make
  156.         //    sure that while we are modifying the list, no one else comes in and changes
  157.         //    anything.
  158.         
  159.         ThreadBeginCritical();
  160.         {
  161.             ThreadID*    nextThread = (**threadList).threads;
  162.             short          numWaiting = (**threadList).numThreads;
  163.             
  164.             while (--numWaiting >= 0)
  165.             {
  166.                 ThreadID blockedThread = *nextThread++;
  167.             
  168.                 theErr = GetThreadState(blockedThread, &blockedThreadState);
  169.     
  170.                 if (blockedThreadState == kStoppedThreadState)
  171.                 {
  172.                     theErr = SetThreadState(blockedThread, kReadyThreadState, kNoThreadID);
  173.                 }
  174.             }
  175.             
  176.             // Now free the list handle (and take it out of the refCon just to be safe)
  177.                         
  178.             DisposeHandle((Handle) threadList);
  179.             
  180.             threadList = nil;
  181.                         
  182.             theErr = AEPutAttributePtr(message, kAERefconAttribute, typeLongInteger,
  183.                                        (Ptr) &threadList, sizeof(threadList));
  184.             
  185.         }
  186.         ThreadEndCritical();
  187.  
  188.     }    
  189.  
  190.     return(theErr);
  191. }
  192.  
  193. pascal OSErr BlockUntilReal(AppleEvent* message)
  194. {
  195.     OSErr            theErr = noErr;
  196.     AERecord        nonExistentParameter;
  197.     
  198.     theErr = AEGetParamDesc(message, kAENonexistantAttribute, typeAERecord,
  199.         &nonExistentParameter);
  200.     
  201.     return(theErr);
  202. }
  203.  
  204. pascal Boolean IsFuture(AppleEvent* message)
  205. {
  206.     OSErr            theErr = noErr;
  207.     ProcPtr            oldBlockingProc;
  208.     Boolean            isFuture = false;
  209.     
  210.     theErr = AEGetSpecialHandler('blck', &oldBlockingProc, false);
  211.     
  212.     if (theErr)
  213.         return(isFuture);
  214.     
  215.     theErr = AEInstallSpecialHandler('blck', (ProcPtr) &IsFutureBlock, false);
  216.     
  217.     if (theErr)
  218.         return(isFuture);
  219.     
  220.     {
  221.         OSErr        blockErr;
  222.         
  223.         blockErr = BlockUntilReal(message);
  224.         theErr   = AEInstallSpecialHandler('blck', oldBlockingProc, false);
  225.         
  226.         if (blockErr == errAEReplyNotArrived)
  227.             isFuture = true;
  228.     }
  229.  
  230.     return(isFuture);
  231. }
  232.  
  233. pascal OSErr IsFutureBlock(AppleEvent* message)
  234. {
  235.     #pragma unused(message);
  236.  
  237.     return(noErr);
  238. }
  239.  
  240. pascal OSErr Ask(AppleEvent* question, AppleEvent* answer)
  241. {
  242.     OSErr            theErr = noErr;
  243.     
  244. //    Send the question with an immediate timeout.
  245.  
  246.     theErr = AESend(question, answer, kAEWaitReply, kAENormalPriority,
  247.             kImmediateTimeout, nil, nil);
  248.     
  249.     if (theErr == errAETimeout)
  250.         theErr = noErr;
  251.  
  252.     return(theErr);
  253. }
  254.